package com.hqyj.config;

import com.hqyj.service.shiro.realm.ShiroAuthorizingRealm;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import java.util.Map;

/**
 * @Description Shiro Config
 * @Author franxhao
 */
@Configuration
@PropertySource("classpath:config/application.properties")
public class ShiroConfig {

    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.timeout}")
    private int timeout;

    private static final String CACHE_KEY = "shiro:cache:";
    private static final String SESSION_KEY = "shiro:session:";
    private static final String NAME = "custom:name:";
    private static final String VALUE = "/";

    /**
     * 整合 shiro 和 Spring Boot
     */
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        // 创建一个 Map 对象包含所有要集成到 Shiro 框架中去的 filter 对象
        // 注册哪些过滤器

        shiroFilterFactoryBean.setSecurityManager(securityManager);

        return shiroFilterFactoryBean;
    }

    /**
     * 创建 SecurityManager 对象，并且装配 Realm 对象
     *
     * @param shiroRealm
     * @return
     */
    @Bean("securityManager")
    public DefaultWebSecurityManager createSecurityManager(@Qualifier("shiroRealm") ShiroAuthorizingRealm shiroRealm) {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager(shiroRealm);
        // 自定义缓存实现 使用shiro
        manager.setCacheManager(cacheManager());
        // 自定义 session管理 使用redis
        manager.setSessionManager(sessionManager());

        /**
         * 关闭 shiro 自带的 session
         */
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        manager.setSubjectDAO(subjectDAO);

        return manager;
    }

    /**
     * Session Manager
     * 使用的是 shiro-redis 开源插件
     */
    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
        // 允许支持基于 Cookie 传递的会话 id
        sessionManager.setSessionIdCookieEnabled(true);
        // 支持请求的 url 重写（通过 url 传递会话id）
        sessionManager.setSessionIdUrlRewritingEnabled(true);

        SimpleCookie simpleCookie = new SimpleCookie();
        simpleCookie.setName(NAME);
        simpleCookie.setValue(VALUE);

        // 设置传递会话id的Cookie的属性
        sessionManager.setSessionIdCookie(simpleCookie);
        return sessionManager;
    }

    /**
     * 准备 RedisSessionDAO
     * RedisSessionDAO shiro sessionDao层的实现 通过 redis
     * 使用的是 shiro-redis开源插件
     */
    @Bean
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        redisSessionDAO.setExpire(86400);
        redisSessionDAO.setKeyPrefix(SESSION_KEY);
        return redisSessionDAO;
    }

    /**
     * cacheManager 缓存 redis实现
     * 使用的是 shiro-redis 开源插件
     */
    public RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        // 装配 redisManager redis管理器
        redisCacheManager.setRedisManager(redisManager());
        redisCacheManager.setExpire(86400);
        redisCacheManager.setKeyPrefix(CACHE_KEY);
        return redisCacheManager;
    }

    /**
     * 配置 shiro redisManager
     * 使用的是 shiro-redis 开源插件
     */
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host);
        redisManager.setPort(port);
        redisManager.setTimeout(timeout);
        return redisManager;
    }
}
